#pragma once
#include <iostream>
#include <cstring>
#include <sys/select.h>
#include <sys/time.h>
#include <string>
#include <memory>
#include "socket.hpp"
#include "log.hpp"

namespace SelectServer
{
    class Select
    {
        static const int defaultfd = -1;
        static const int maxcap = sizeof(fd_set) * 8;

    public:
        Select(uint16_t port)
            : _listenfd(new SocketInter::SockIn(port))
        {
            memset(_fd_arr, defaultfd, sizeof(_fd_arr));
        }
        void Init()
        {
            _listenfd->InitSockaddr();
            _listenfd->Socket();
            _listenfd->Bind();
            _listenfd->Listen();
        }
        void run()
        {
            _fd_arr[0] = _listenfd->listenfd();
            while (true)
            {
                fd_set nfds;
                FD_ZERO(&nfds);
                int maxfd = _fd_arr[0];
                for (int i = 0; i < maxcap; i++)
                {
                    if (_fd_arr[i] == defaultfd)
                        continue;
                    FD_SET(_fd_arr[i],&nfds);   
                    
                    if (maxfd < _fd_arr[i])
                    {
                        maxfd = _fd_arr[i];
                    }
                }

                timeval timeout = {5, 0}; // 设置等待时间间隔
                int n = select(maxfd + 1, &nfds, nullptr, nullptr, &timeout);
                switch (n)
                {
                case 0:
                    std::cout << "超时" << std::endl;
                    break;
                case -1:
                    std::cout << "select errno:" << errno << ",strerror:" << strerror(errno) << std::endl;
                    break;
                default:
                    Distribution(nfds);
                }
            }
        }

        void Distribution(fd_set &nfds)
        {
            for (int i = 0; i < maxcap; i++)
            {
                int fd = _fd_arr[i];
                if (fd == defaultfd)
                    continue;
                
                if (FD_ISSET(fd, &nfds))
                {
                    if (fd == _listenfd->listenfd())
                    {
                        GetLink();
                    }
                    else
                    {
                        EventReady(fd,i);
                    }
                }
            }
        }

        void GetLink() // 获取连接
        {
            int sock = _listenfd->Accept();
            std::cout << "获取链接成功" << std::endl; 
            bool fill = true;
            for (int i = 0; i < maxcap; i++)
            {
                if (_fd_arr[i] == defaultfd)
                {
                    _fd_arr[i] = sock;
                    fill = false;
                    break;
                }
            }

            if (fill)
            {
                std::cout << "连接满载" << std::endl;
                close(sock);
            }

            std::string ip = _listenfd->GetClientip();
            uint16_t port = _listenfd->GetClientport();

            mylog::log(Info, "客户端ip:%s,端口号:%d", ip.c_str(), port);
        }

        void EventReady(int fd,int pos) // 事件就绪
        {
            char bufstr[1024];
            int n = read(fd, bufstr, sizeof(bufstr));
            if (n > 0)
            {
                std::cout << bufstr << std::endl;
            }
            else if (n == 0)
            {
                std::cout << "写端退出" << std::endl;
                close(fd);
                _fd_arr[pos] = defaultfd;
            }
            else
            {
                if (errno == EWOULDBLOCK)
                {
                    std::cout << "暂无数据可读" << std::endl;
                }
                else
                {
                    std::cout << "读取失败" << std::endl;
                    close(fd);
                    _fd_arr[pos] = defaultfd;
                }
            }
        }


    private:
        std::shared_ptr<SocketInter::SockIn> _listenfd;
        int _fd_arr[maxcap];
    };
}